package com.cs.base.jpa.support;

import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author wangjiahao
 * @version 1.0
 * @className JpaUtils
 * @since 2019-01-25 19:24
 */
public class JpaUtils {

    public static Specification eqRelationShip(Object r, String relationFieldName) {
        return (root, query, cb) -> {
            ArrayList<Predicate> list = new ArrayList<>();
            Join join = root.join(relationFieldName, JoinType.LEFT);
            List<String> fields = getFields(r);
            fields.forEach(f -> {
                Object value = getFieldValue(r, f);
                if (Objects.nonNull(value)) {
                    list.add(cb.equal(join.get(f), value));
                }
            });
            return query.where(list.toArray(new Predicate[0])).getRestriction();
        };
    }

    public static Specification likeRelationShip(Object r, String rField, String relationFieldName) {
        return (root, query, cb) -> {
            ArrayList<Predicate> list = new ArrayList<>();
            Join join = root.join(relationFieldName, JoinType.LEFT);
            List<String> fields = getFields(r);
            fields.forEach(f -> {
                Object value = getFieldValue(r, f);
                if (Objects.nonNull(value)) {
                    list.add(cb.like(join.get(rField),value.toString()));
                }
            });
            return query.where(list.toArray(new Predicate[0])).getRestriction();
        };
    }


    static <T> List<String> getFields(T t) {
        Field[] fields = t.getClass().getDeclaredFields();
        return Stream.of(fields).map(Field::getName).collect(Collectors.toList());
    }

    static <T> Object getFieldValue(T t, String fieldName) {
        try {
            Field field = t.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(t);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

}
